#include "../lib_include/Socket.h"
#include "../lib_include/Logger.h"
#include "../lib_include/InetAddress.h"
#include "../lib_include/SocketsOps.h"

#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>  // snprintf

using namespace netlib;
using namespace netlib::net;

Socket::~Socket() { sockets::close(sockfd_); }

// 获取TCP相关信息
bool Socket::getTcpInfo(struct tcp_info* tcpi) const
{
    socklen_t len = sizeof(*tcpi);
    memZero(tcpi, len);
    return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0;
}

// 获取TCP相关信息并将其转化成字符串
bool Socket::getTcpInfoString(char* buf, int len) const
{
    struct tcp_info tcpi;
    bool ok = getTcpInfo(&tcpi);
    if (ok)
    {
        snprintf(buf, len, "unrecovered=%u "
                "rto=%u ato=%u snd_mss=%u rcv_mss=%u "
                "lost=%u retrans=%u rtt=%u rttvar=%u "
                "sshthresh=%u cwnd=%u total_retrans=%u",
                tcpi.tcpi_retransmits,  // Number of unrecovered [RTO] timeouts
                tcpi.tcpi_rto,          // Retransmit timeout in usec
                tcpi.tcpi_ato,          // Predicted tick of soft clock in usec
                tcpi.tcpi_snd_mss,
                tcpi.tcpi_rcv_mss,
                tcpi.tcpi_lost,         // Lost packets
                tcpi.tcpi_retrans,      // Retransmitted packets out
                tcpi.tcpi_rtt,          // Smoothed round trip time in usec
                tcpi.tcpi_rttvar,       // Medium deviation
                tcpi.tcpi_snd_ssthresh,
                tcpi.tcpi_snd_cwnd,
                tcpi.tcpi_total_retrans);  // Total retransmits for entire connection
    }
    return ok;
}

// 调用自己封装的bind
void Socket::bindAddress(const InetAddress& addr)
{ sockets::bindOrDie(sockfd_, addr.getSockAddr()); }

// 调用自己封装的listen
void Socket::listen() { sockets::listenOrDie(sockfd_); }

// 调用自己封装的accept
int Socket::accept(InetAddress* peeraddr)
{
    struct sockaddr_in6 addr;
    memZero(&addr, sizeof addr);
    int connfd = sockets::accept(sockfd_, &addr);
    if (connfd >= 0)
        peeraddr->setSockAddrInet6(addr);
    return connfd;
}

// 调用自己封装的shutdown
void Socket::shutdownWrite() { sockets::shutdownWrite(sockfd_); }

// Nagle算法可以一定程度上避免网络拥塞，连续发送的小包，攒到一定的量再发送
// TCP_NODELAY选项可以禁用Nagle算法，小包直接发送，不等到攒到大包
// 禁用Nagle算法，可以避免连续发包出现延迟，对于低延迟服务很重要
void Socket::setTcpNoDelay(bool on)
{
    int optval = on ? 1 : 0; // on为真则禁用Nagle算法
    ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY,
                &optval, static_cast<socklen_t>(sizeof optval));
}

// 设置地址重复利用，端口复用
void Socket::setReuseAddr(bool on)
{
    int optval = on ? 1 : 0;
    ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
                &optval, static_cast<socklen_t>(sizeof optval));
}


void Socket::setReusePort(bool on)
{
    #ifdef SO_REUSEPORT
    int optval = on ? 1 : 0;
    int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT,
                            &optval, static_cast<socklen_t>(sizeof optval));
    if (ret < 0 && on)
        LOG_SYSERR << "SO_REUSEPORT failed.";
    #else
    if (on)
        LOG_ERROR << "SO_REUSEPORT is not supported.";
    #endif
}

// 定期检测连接是否存在，应用层有心跳机制则无需设置该函数
void Socket::setKeepAlive(bool on)
{
    int optval = on ? 1 : 0; // on表示开启内核层TCP的心跳机制
    ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE,
                &optval, static_cast<socklen_t>(sizeof optval));
}

